<script lang="ts" setup>
import { PropType } from 'vue'
import { Editor, Toolbar } from '@wangeditor-next/editor-for-vue'
import {
  Boot,
  i18nChangeLanguage,
  IDomEditor,
  IEditorConfig,
  IToolbarConfig
} from '@wangeditor-next/editor'
import { propTypes } from '@/utils/propTypes'
import { isNumber } from '@/utils/is'
import { ElMessage } from 'element-plus'
import { useLocaleStore } from '@/store/modules/locale'
import { getAccessToken, getTenantId } from '@/utils/auth'
import { getSiteHeader } from '@/utils/cmscommon'
import formulaModule from '@wangeditor/plugin-formula'
import { useUserStore } from '@/store/modules/user'

defineOptions({ name: 'Editor' })

type InsertFnType = (url: string, alt: string, href: string) => void
type InsertVideoFnType = (url: string, poster: string) => void

const localeStore = useLocaleStore()

const currentLocale = computed(() => localeStore.getCurrentLocale)

i18nChangeLanguage(unref(currentLocale).lang)

const props = defineProps({
  editorId: propTypes.string.def('wangeEditor-1'),
  height: propTypes.oneOfType([Number, String]).def('500px'),
  editorConfig: {
    type: Object as PropType<Partial<IEditorConfig>>,
    default: () => undefined
  },
  toolbarConfig: {
    type: Object as PropType<Partial<IToolbarConfig>>,
    default: () => undefined
  },
  readonly: propTypes.bool.def(false),
  modelValue: propTypes.string.def('')
})

const emit = defineEmits(['change', 'update:modelValue', 'blur'])

// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef<IDomEditor>()
const valueHtml = ref('')

watch(
  () => props.modelValue,
  (val: string) => {
    if (val === unref(valueHtml)) return
    valueHtml.value = val
  },
  {
    immediate: true
  }
)

// 监听
watch(
  () => valueHtml.value,
  (val: string) => {
    //div标签显示有问题，移除掉
    val = removeDivTag(val)
    emit('update:modelValue', val)
  }
)
const  removeDivTag  = (htmlString) => {
  // 去除div
  const regex = new RegExp('<div'+'.*', 'g'); 
  htmlString = htmlString.replace(regex, "");
  htmlString = htmlString.replace("</div>","")
  return htmlString;
}
 
const handleCreated = (editor: IDomEditor) => {
  //注册数学公式插件 formula
  if (useUserStore().grade >= 1) {
    if (!editor.getAllMenuKeys()?.includes('insertFormula')) {
      Boot.registerModule(formulaModule)
    }
  }
  editorRef.value = editor
}

// 编辑器配置
const editorConfig = computed((): IEditorConfig => {
  return Object.assign(
    {
      placeholder: '请输入内容...',
      readOnly: props.readonly,
      customAlert: (s: string, t: string) => {
        switch (t) {
          case 'success':
            ElMessage.success(s)
            break
          case 'info':
            ElMessage.info(s)
            break
          case 'warning':
            ElMessage.warning(s)
            break
          case 'error':
            ElMessage.error(s)
            break
          default:
            ElMessage.info(s)
            break
        }
      },
      autoFocus: false,
      scroll: true,
      MENU_CONF: {
        ['uploadImage']: {
          server: import.meta.env.VITE_IMAGE_UPLOAD_URL,
          // 单个文件的最大体积限制，默认为 50M
          maxFileSize: 50 * 1024 * 1024,
          // 最多可上传几个文件，默认为 100
          maxNumberOfFiles: 100,
          // 选择文件时的类型限制，默认为 ['image/*'] 。如不想限制，则设置为 []
          allowedFileTypes: ['image/*'],
          // 自定义上传参数,参数会被添加到 formData 中，一起上传到服务端。
          meta: {
            uploadEditor: true,
            Authorization: 'Bearer ' + getAccessToken(),
            'tenant-id': getTenantId(),
            zrcms_site_id: getSiteHeader()
          },
          // 自定义增加 http  header
          headers: {
            Accept: '*',
            Authorization: 'Bearer ' + getAccessToken(),
            'tenant-id': getTenantId(),
            zrcms_site_id: getSiteHeader()
          },

          // 跨域是否传递 cookie ，默认为 false
          // 上传图片跨域
          withCredentials: false,

          // 超时时间，默认为 10 秒
          timeout: 10 * 1000, // 10 秒

          // form-data fieldName，后端接口参数名称，默认值wangeditor-uploaded-image
          fieldName: 'file',
          customInsert(res: any, insertFn: InsertFnType) {  // TS 语法
            console.log("res->",res)
            //不成功，提示原因
            if (res.code != 0) {
              alert('上传失败:' + res.msg)
            }
            insertFn(res.data.url, 'image', res.data.url)
          },
        },
        ['uploadVideo']: {
          server: import.meta.env.VITE_VIDEO_UPLOAD_URL,
          // 单个文件的最大体积限制，默认为 5g
          maxFileSize: 5 * 1024 * 1024 * 1024,
          // 最多可上传几个文件，默认为 10
          maxNumberOfFiles: 10,
          // 选择文件时的类型限制，默认为 ['video/*'] 。如不想限制，则设置为 []
          allowedFileTypes: ['video/*'],

          // 自定义上传参数，例如传递验证的 token 等。参数会被添加到 formData 中，一起上传到服务端。
          meta: { updateSupport: 0 },
          // 将 meta 拼接到 url 参数中，默认 false
          metaWithUrl: true,

          // 自定义增加 http  header
          headers: {
            Accept: '*',
            Authorization: 'Bearer ' + getAccessToken(),
            'tenant-id': getTenantId(),
            zrcms_site_id: getSiteHeader()
          },

          // 跨域是否传递 cookie ，默认为 false
          // 上传图片跨域
          withCredentials: false,

          // 超时时间，默认为 2 小时
          timeout: 2 * 3600 * 1000, // 2 小时

          // form-data fieldName，后端接口参数名称，默认值wangeditor-uploaded-image
          fieldName: 'file',
          // 自定义插入视频
          customInsert(res: any, insertFn: InsertVideoFnType) {
            console.log("res->",res)
            //不成功，提示原因
            if (res.code != 0) {
              alert('上传失败:' + res.msg)
            }
            insertFn(res.data.url, res.data.posterUrl)
          }
        }
      },
      uploadImgShowBase64: true,
      // 选中公式时的悬浮菜单
      hoverbarKeys: {
        formula: {
          menuKeys: ['editFormula'] // “编辑公式”菜单
        }
      }
    },
    props.editorConfig || {}
  )
})

const toolbarConfig = computed((): IToolbarConfig => {
  const defToolBarConfig = props.toolbarConfig || {}
  // //判断如果已经插入进去，不在二次插入
  return Object.assign(
    {
      insertKeys: {
        index: 21,
        keys: [
          'insertFormula', // “插入公式”菜单
          'editFormula' // “编辑公式”菜单
        ]
      }
    },
    defToolBarConfig
  )
})

const editorStyle = computed(() => {
  return {
    height: isNumber(props.height) ? `${props.height}px` : props.height
  }
})

// 回调函数
const handleChange = (editor: IDomEditor) => {
  emit('change', editor)
}

const handleBlur = (editor: IDomEditor) => {
  emit('blur', editor)
}
const handleCustomPaste = async ( editor: IDomEditor,event: ClipboardEvent): boolean => {
  // 继续执行默认的粘贴行为
  const items = (event.clipboardData || event.originalEvent.clipboardData).items;
  for (let i = 0; i < items.length; i++) {
    if (items[i].kind === 'file' && items[i].type.indexOf('image/') !== -1) {
      const file = items[i].getAsFile();
      console.log("file->",file)
    }
  }
  return true
}

// 组件销毁时，及时销毁编辑器
onBeforeUnmount(() => {
  const editor = unref(editorRef.value)

  // 销毁，并移除 editor
  editor?.destroy()
})

const getEditorRef = async (): Promise<IDomEditor> => {
  await nextTick()
  return unref(editorRef.value) as IDomEditor
}

defineExpose({
  getEditorRef
})
</script>

<template>
  <div class="border-1 border-solid border-[var(--tags-view-border-color)] z-10">
    <!-- 工具栏 -->
    <Toolbar
      :editor="editorRef"
      :editorId="editorId"
      class="border-0 b-b-1 border-solid border-[var(--tags-view-border-color)]"
      :defaultConfig="toolbarConfig"
    />
    <!-- 编辑器 -->
    <Editor
      v-model="valueHtml"
      :defaultConfig="editorConfig"
      :editorId="editorId"
      :style="editorStyle"
      @on-change="handleChange"
      @on-created="handleCreated"
      @on-blur="handleBlur"
      @customPaste="handleCustomPaste"
    />
  </div>
</template>
<style src="@wangeditor-next/editor/dist/css/style.css"></style>
